﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using System.Windows.Threading;
namespace DevExpress.AgMenu {
	public enum AgPopupAnimationType {
		None,
		Fade,
		Slide,
		Scroll
	}
}
namespace DevExpress.AgMenu.Internal {
	public class AgAnimatedPopup {
		const double AnimationDuration = 300;
		Canvas canvas;
		UIElement child;
		double horizontalOffset;
		bool isOpen;
		Popup popup;
		int startTickCount;
		DispatcherTimer timer;
		double verticalOffset;
		public UIElement Child {
			get { return child; }
			set {
				if (value == child) return;
				child = value;
				ChildChanged();
			}
		}
		public double HorizontalOffset {
			get { return horizontalOffset; }
			set {
				if (value == horizontalOffset) return;
				horizontalOffset = value;
				HorizontalOffsetChanged();
			}
		}
		public bool IsBottomToTopAnimation { get; set; }
		public bool IsOpen {
			get { return isOpen; }
			set {
				if (value == isOpen) return;
				isOpen = value;
				IsOpenChanged();
			}
		}
		public bool IsRightToLeftAnimation { get; set; }
		public Orientation SlideOrientation { get; set; }
		public double VerticalOffset {
			get { return verticalOffset; }
			set {
				if (value == verticalOffset) return;
				verticalOffset = value;
				VerticalOffsetChanged();
			}
		}
		public event EventHandler Closed;
		public event EventHandler Opened;
		public AgAnimatedPopup(Control ownerControl) : this(ownerControl, null) { }
		public AgAnimatedPopup(Control ownerControl, Popup externalPopup) {
			popup = externalPopup;
			if (popup == null)
				popup = new Popup();
			ContentControl backgroundControl = new ContentControl() { Width = 0, Height = 0 };
			if (ownerControl != null)
				AssignInheritableProperties(ownerControl, backgroundControl);
			popup.Child = backgroundControl;
			canvas = new Canvas();
			backgroundControl.Content = canvas;
			popup.Closed += OnClosed;
			popup.Opened += OnOpened;
			timer = new DispatcherTimer();
			timer.Interval = TimeSpan.FromMilliseconds(10);
			timer.Tick += OnTimerTick;
		}
		public virtual bool Animate(AgPopupAnimationType animationType) {
			if (Child == null)
				throw new Exception();
			switch (animationType) {
				case AgPopupAnimationType.Fade:
					DoFadeAnimation();
					break;
				case AgPopupAnimationType.Slide:
					DoSlideAnimation();
					break;
				case AgPopupAnimationType.Scroll:
					DoScrollAnimation();
					break;
			}
			return animationType != AgPopupAnimationType.None;
		}
		protected virtual void ChildChanged() {
			canvas.Children.Clear();
			if (Child != null)
				canvas.Children.Add(Child);
		}
		protected virtual void DoFadeAnimation() {
			canvas.Opacity = 0;
			Storyboard s = new Storyboard();
			s.Children.Add(CreateOpacityAnimation());
			s.Begin();
		}
		protected virtual void DoScrollAnimation() {
			if (SlideOrientation == Orientation.Horizontal) {
				if (IsRightToLeftAnimation)
					canvas.Clip = new RectangleGeometry() { Rect = new Rect(Child.DesiredSize.Width, 0, 0, Application.Current.Host.Content.ActualHeight) };
				else
					canvas.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, 0, Application.Current.Host.Content.ActualHeight) };
			} else {
				if (IsBottomToTopAnimation)
					canvas.Clip = new RectangleGeometry() { Rect = new Rect(0, child.DesiredSize.Height, Application.Current.Host.Content.ActualWidth, 0) };
				else
					canvas.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, Application.Current.Host.Content.ActualWidth, 0) };
			}
			startTickCount = Environment.TickCount;
			timer.Start();
		}
		protected virtual void DoSlideAnimation() {
			if (IsRightToLeftAnimation || IsBottomToTopAnimation)
				canvas.Clip = new RectangleGeometry() {
					Rect = new Rect(0, 0, Child.DesiredSize.Width, Child.DesiredSize.Height)
				};
			else
				canvas.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, Application.Current.Host.Content.ActualWidth, Application.Current.Host.Content.ActualHeight) };
			TranslateTransform t = new TranslateTransform();
			Child.RenderTransform = t;
			Storyboard s = new Storyboard();
			DoubleAnimation a = new DoubleAnimation();
			Storyboard.SetTarget(a, t);
			InitSlideAnimation(a);
			s.Children.Add(a);
			s.Begin();
		}
		protected virtual void HorizontalOffsetChanged() {
			popup.HorizontalOffset = HorizontalOffset;
		}
		protected virtual void IsOpenChanged() {
			popup.IsOpen = IsOpen;
		}
		protected virtual void OnClosed(object sender, EventArgs e) {
			popup.Closed -= OnClosed;
			RaiseClosed();
		}
		protected virtual void OnOpened(object sender, EventArgs e) {
			popup.Opened -= OnOpened;
			RaiseOpened();
		}
		protected virtual void RaiseClosed() {
			if (Closed != null)
				Closed(this, new EventArgs());
		}
		protected virtual void RaiseOpened() {
			if (Opened != null)
				Opened(this, new EventArgs());
		}
		protected virtual void VerticalOffsetChanged() {
			popup.VerticalOffset = VerticalOffset;
		}
		void AssignInheritableProperties(Control source, Control destination) {
			destination.FontFamily = source.FontFamily;
			destination.FontSize = source.FontSize;
		}
		DoubleAnimation CreateOpacityAnimation() {
			DoubleAnimation result = new DoubleAnimation();
			Storyboard.SetTarget(result, canvas);
			Storyboard.SetTargetProperty(result, new PropertyPath("Opacity"));
			result.From = 0;
			result.To = 1;
			result.Duration = new Duration(TimeSpan.FromMilliseconds(AnimationDuration));
			return result;
		}
		void InitHorizontalDoubleAnimation(DoubleAnimation animation) {
			Storyboard.SetTargetProperty(animation, new PropertyPath("X"));
			if (IsRightToLeftAnimation) {
				animation.From = Child.DesiredSize.Width;
				animation.To = 0;
			} else {
				animation.From = -Child.DesiredSize.Width;
				animation.To = 0;
			}
			animation.Duration = new Duration(TimeSpan.FromMilliseconds(AnimationDuration));
			((TranslateTransform)Child.RenderTransform).X = (double)animation.From;
		}
		void InitSlideAnimation(DoubleAnimation animation) {
			if (SlideOrientation == Orientation.Horizontal)
				InitHorizontalDoubleAnimation(animation);
			else
				InitVerticalDoubleAnimation(animation);
		}
		void InitVerticalDoubleAnimation(DoubleAnimation animation) {
			Storyboard.SetTargetProperty(animation, new PropertyPath("Y"));
			if (IsBottomToTopAnimation) {
				animation.From = Child.DesiredSize.Height;
				animation.To = 0;
			} else {
				animation.From = -Child.DesiredSize.Height;
				animation.To = 0;
			}
			animation.Duration = new Duration(TimeSpan.FromMilliseconds(AnimationDuration));
			((TranslateTransform)Child.RenderTransform).Y = (double)animation.From;
		}
		void OnTimerTick(object sender, EventArgs e) {
			int tickCount = Environment.TickCount;
			if (tickCount - startTickCount > AnimationDuration) {
				timer.Stop();
				canvas.Clip = new RectangleGeometry() { Rect = new Rect(0, 0, Child.DesiredSize.Width, Child.DesiredSize.Height) };
			} else {
				if (SlideOrientation == Orientation.Horizontal) {
					if (IsRightToLeftAnimation) {
						double visiblePartWidth = (tickCount - startTickCount) * Child.DesiredSize.Width / AnimationDuration;
						canvas.Clip = new RectangleGeometry() {
							Rect = new Rect(Child.DesiredSize.Width - visiblePartWidth, 0,
								visiblePartWidth, Application.Current.Host.Content.ActualHeight)
						};
					} else {
						canvas.Clip = new RectangleGeometry() {
							Rect = new Rect(0, 0,
								(tickCount - startTickCount) * Child.DesiredSize.Width / AnimationDuration, Application.Current.Host.Content.ActualHeight)
						};
					}
				} else {
					if (IsBottomToTopAnimation) {
						double visiblePartHeight = (tickCount - startTickCount) * Child.DesiredSize.Height / AnimationDuration;
						canvas.Clip = new RectangleGeometry() {
							Rect = new Rect(0, child.DesiredSize.Height - visiblePartHeight,
								Application.Current.Host.Content.ActualWidth, visiblePartHeight)
						};
					} else {
						canvas.Clip = new RectangleGeometry() {
							Rect = new Rect(0, 0,
								Application.Current.Host.Content.ActualWidth, (tickCount - startTickCount) * Child.DesiredSize.Height / AnimationDuration)
						};
					}
				}
			}
		}
	}
}
